﻿namespace AbpPlus.Bus
{
	using System.Threading.Tasks;

	using AbpPlus.Commands;
	using AbpPlus.Events;

	using MediatR;

	/// <summary>
	/// The in memory bus.
	/// </summary>
	public sealed class InMemoryBus : IMediatorHandler
	{
		/// <summary>
		/// The _mediator.
		/// </summary>
		private readonly IMediator _mediator;

		/// <summary>
		/// The _event store.
		/// </summary>
		private readonly IEventStore _eventStore;

		/// <summary>
		/// Initializes a new instance of the <see cref="InMemoryBus"/> class.
		/// </summary>
		/// <param name="eventStore">
		/// The event store.
		/// </param>
		/// <param name="mediator">
		/// The mediator.
		/// </param>
		public InMemoryBus(IEventStore eventStore, IMediator mediator)
		{
			this._eventStore = eventStore;
			this._mediator = mediator;
		}

		/// <summary>
		/// The send command.
		/// </summary>
		/// <param name="command">
		/// The command.
		/// </param>
		/// <typeparam name="T">
		/// </typeparam>
		/// <returns>
		/// The <see cref="Task"/>.
		/// </returns>
		public Task SendCommand<T>(T command) where T : Command
		{
			return this._mediator.Send(command);
		}

		/// <summary>
		/// The send with result.
		/// </summary>
		/// <param name="command">
		/// The command.
		/// </param>
		/// <typeparam name="TCommand">
		/// </typeparam>
		/// <typeparam name="TCommandResult">
		/// </typeparam>
		/// <returns>
		/// The <see cref="Task"/>.
		/// </returns>
		public Task<TCommandResult> SendWithResult<TCommand, TCommandResult>(TCommand command)
			where TCommand : Command<TCommandResult>
		{
			return this._mediator.Send(command);
		}

		/// <summary>
		/// The raise event.
		/// </summary>
		/// <param name="event">
		/// The event.
		/// </param>
		/// <typeparam name="T">
		/// </typeparam>
		/// <returns>
		/// The <see cref="Task"/>.
		/// </returns>
		public Task RaiseEvent<T>(T @event) where T : Event
		{
			if (!@event.MessageType.Equals("DomainNotification"))
			{
				this._eventStore?.Save(@event);
			}

			return this.Publish(@event);
		}

		/// <summary>
		/// The publish.
		/// </summary>
		/// <param name="message">
		/// The message.
		/// </param>
		/// <typeparam name="T">
		/// </typeparam>
		/// <returns>
		/// The <see cref="Task"/>.
		/// </returns>
		private Task Publish<T>(T message) where T : Message
		{
			return this._mediator.Publish(message);
		}
	}
}